When writing code during the development of software applications, developers commonly spend a significant amount of time “debugging” the code to find runtime errors in the code. In doing so, developers may take several approaches to reproduce and localize a source code bug, such as observing behavior of a program based on different inputs, inserting debugging code (e.g., to print variable values, to track branches of execution, etc.), temporarily removing code portions, etc. Tracking down runtime errors to pinpoint code bugs can occupy a significant portion of application development time.
Many types of debugging applications (“debuggers”) have been developed in order to assist developers with the code debugging process. These tools offer developers the ability to trace, visualize, and alter the execution of computer code. For example, debuggers may visualize the execution of code instructions, may present variable values at various times during code execution, may enable developers to alter code execution paths, and/or may enable developers to set “breakpoints” in code (which, when reached during execution, causes execution of the code to be suspended), among other things.
An emerging form of debugging applications enable “time travel,” “reverse,” or “historic” debugging, in which execution of a program is recorded/traced by a trace application into one or more trace files, which can be then be used to replay execution of the program for forward and backward analysis. For example, “time travel” debuggers can enable a developer to set forward breakpoints (like conventional debuggers) as well as reverse breakpoints.
However, due to the need to replay code execution, “time travel” debuggers can exhibit poor responsiveness. For example, there may be a significant delay between the time that a user issues a debugging operation (e.g., single step forward/backward, step over forward/backward, go forward/backward) and the “time travel” debugger “hits” the breakpoint and presents the results to the user, since the debugger needs to perform a trace replay of potentially billions of instructions in response to the user input.